package com.viking.XFT;

import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.provider.Settings;
import android.view.*;
import android.widget.ImageView;
import java.util.List;


public class FloatManager {
    //static final String TAG = "FloatManager";
    static final float float_button_alpha = (float)0.25;

    static private FloatManager float_manager = null;

    private Context context = null;

    private WindowManager window_manager = null;
    private DevicePolicyManager device_policy_manager = null;
    private ComponentName admin_component = null;

    static enum FLOAT_VIEW_TYPE {
        FLOAT_BUTTON,
        FLOAT_MENU
    }
    private FLOAT_VIEW_TYPE current_float_view = FLOAT_VIEW_TYPE.FLOAT_BUTTON;

    private ImageView float_button = null;
    private WindowManager.LayoutParams float_button_layout_params = null;

    private View float_menu = null;
    private WindowManager.LayoutParams float_menu_layout_params = null;

    private int status_bar_height = 0;
    private int stick_distance = 0;

    private int screen_width = 0;
    private int screen_height = 0;


    private GestureDetector gesture_detector = null;
    private float dx= (float) 0.0;
    private float dy= (float) 0.0;

    private ValueAnimator anim_fadeout = null;

    static FloatManager getInstance(Context context) {
        if (null == float_manager) {
            float_manager = new FloatManager(context);
        }
        return float_manager;
    }

    private FloatManager(Context context) {
        this.context = context;
        window_manager = (WindowManager) (context.getSystemService(Context.WINDOW_SERVICE));
        Point size = new Point();
        window_manager.getDefaultDisplay().getSize(size);
        screen_width = size.x;
        screen_height = size.y; // window_manager.getDefaultDisplay().getHeight();
        //Log.d(TAG, String.format("Size: %d  %d", screen_width, screen_height));

        initFloatButton(context);
        initFloatMenu(context);

        device_policy_manager = (DevicePolicyManager) (context.getSystemService(Context.DEVICE_POLICY_SERVICE));
        admin_component = new ComponentName(context.getApplicationInfo().packageName, XFTDeviceAdminReceiver.class.getName());
    }

    private void initFloatMenu(Context context) {
        float_menu = new FloatMenu(context);
        Drawable bg = context.getResources().getDrawable(R.drawable.float_menu_bg);
        float_menu_layout_params = new WindowManager.LayoutParams();
        float_menu_layout_params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
        float_menu_layout_params.format = PixelFormat.RGBA_8888;
        float_menu_layout_params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        float_menu_layout_params.gravity = Gravity.LEFT | Gravity.TOP;
        float_menu_layout_params.width = bg.getMinimumWidth(); // WindowManager.LayoutParams.WRAP_CONTENT;
        float_menu_layout_params.height = bg.getMinimumHeight(); // WindowManager.LayoutParams.WRAP_CONTENT;
        float_menu_layout_params.x = (screen_width - float_menu_layout_params.width) / 2;
        float_menu_layout_params.y = (screen_height - float_menu_layout_params.height) / 2;
    }

    private void initFloatButton(Context context) {
        gesture_detector = new GestureDetector(context, new FloatButtonGestureListener());

        ValueAnimator.setFrameDelay(50);
        anim_fadeout = ValueAnimator.ofFloat(1.0f, float_button_alpha);
        anim_fadeout.setDuration(2000);
        anim_fadeout.setStartDelay(1000);
        anim_fadeout.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (current_float_view == FLOAT_VIEW_TYPE.FLOAT_BUTTON) {
                    float_button_layout_params.alpha = (Float) (animation.getAnimatedValue());
                    window_manager.updateViewLayout(float_button, float_button_layout_params);
                } else {
                    animation.cancel();
                }
            }
        });

        Drawable bg = context.getResources().getDrawable(R.drawable.btn_assistivetouch);
        float_button = new ImageView(context);
        float_button.setImageDrawable(bg);// .setBackgroundDrawable(bg);
        float_button.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                return gesture_detector.onTouchEvent(event);
            }
        });

        float_button_layout_params = new WindowManager.LayoutParams();
        float_button_layout_params.type = WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
        float_button_layout_params.format = PixelFormat.RGBA_8888;
        float_button_layout_params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
        float_button_layout_params.gravity = Gravity.LEFT | Gravity.TOP;
        float_button_layout_params.x = screen_width;
        float_button_layout_params.y = screen_height / 4;
        float_button_layout_params.width = bg.getMinimumWidth(); // WindowManager.LayoutParams.WRAP_CONTENT;
        float_button_layout_params.height = bg.getMinimumHeight(); // WindowManager.LayoutParams.WRAP_CONTENT;
        float_button_layout_params.alpha = float_button_alpha;
    }

    private class FloatButtonGestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onDown(MotionEvent e) {
            dx = e.getX();
            dy = e.getY();
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            moveFloatButton((int) (e2.getRawX() - dx), (int) (e2.getRawY() - dy - status_bar_height));
            if (anim_fadeout.isStarted()) {
                anim_fadeout.cancel();
            }
            anim_fadeout.start();
            return true;
        }

        private void moveFloatButton(int x, int y) {
            Point size = new Point();
            window_manager.getDefaultDisplay().getSize(size);
            screen_width = size.x;
            screen_height = size.y;

            if (x <= stick_distance) {
                x = 0;
            } else if (x >= screen_width - stick_distance - float_button_layout_params.width) {
                x = screen_width;
            }

            if (y <= stick_distance) {
                y = 0;
            } else if (y >= screen_height - status_bar_height - stick_distance - float_button_layout_params.height) {
                y = screen_height;
            }
            //Log.d(TAG, String.format("update float: %d %d", x, y));
            float_button_layout_params.x = x;
            float_button_layout_params.y = y;
            float_button_layout_params.alpha = 1.0f;
            window_manager.updateViewLayout(float_button, float_button_layout_params);
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            goHome();
            lockScreen();
            return true;
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            shiftFloat(FLOAT_VIEW_TYPE.FLOAT_MENU);
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            openRecentApp();
        }
    }

    public void addFloat() {
        if (FLOAT_VIEW_TYPE.FLOAT_BUTTON == current_float_view) {
            window_manager.addView(float_button, float_button_layout_params);
        } else {
            window_manager.addView(float_menu, float_menu_layout_params);
        }
    }

    public void removeFloat() {
        if (FLOAT_VIEW_TYPE.FLOAT_BUTTON == current_float_view) {
            window_manager.removeView(float_button);
        } else {
            window_manager.removeView(float_menu);
        }
    }

    public void shiftFloat(FLOAT_VIEW_TYPE float_view) {
        if (float_view == current_float_view) {
            return;
        }

        Point size = new Point();
        window_manager.getDefaultDisplay().getSize(size);
        screen_width = size.x;
        screen_height = size.y;

        if (FLOAT_VIEW_TYPE.FLOAT_BUTTON == current_float_view) {
            current_float_view = FLOAT_VIEW_TYPE.FLOAT_MENU;
            window_manager.removeView(float_button);
            float_menu_layout_params.x = (screen_width - float_menu_layout_params.width) / 2;
            float_menu_layout_params.y = (screen_height - float_menu_layout_params.height) / 2;
            window_manager.addView(float_menu, float_menu_layout_params);
        } else {
            current_float_view = FLOAT_VIEW_TYPE.FLOAT_BUTTON;
            window_manager.removeView(float_menu);
            float_button_layout_params.alpha = 1.0f;
            window_manager.addView(float_button, float_button_layout_params);
            anim_fadeout.cancel();
            anim_fadeout.start();
        }
    }

    public void setStatusBarHeight(int height) {
        status_bar_height = height;
        stick_distance = height * 2;
    }

    public void goHome() {
        shiftFloat(FLOAT_VIEW_TYPE.FLOAT_BUTTON);

        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        context.startActivity(intent);
    }

    public void lockScreen() {
        shiftFloat(FLOAT_VIEW_TYPE.FLOAT_BUTTON);

        if (device_policy_manager.isAdminActive(admin_component)) {
            device_policy_manager.lockNow();
        }
    }

    public void openSetting() {
        shiftFloat(FLOAT_VIEW_TYPE.FLOAT_BUTTON);

        Intent intent = new Intent(Settings.ACTION_SETTINGS);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        context.startActivity(intent);
    }

    public void openRecentApp() {
        shiftFloat(FLOAT_VIEW_TYPE.FLOAT_BUTTON);

        try {
            Intent intent = new Intent("/");
            intent.setComponent(new ComponentName("com.android.systemui", "com.android.systemui.recent.RecentsActivity"));
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            e.printStackTrace();
            //todo: Show customize recent app view
        }
    }

    public void openPreviousApp() {
        shiftFloat(FLOAT_VIEW_TYPE.FLOAT_BUTTON);

        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(3);
        if (3 == tasks.size()) {
            ActivityManager.RunningTaskInfo task = tasks.get(2);
            am.moveTaskToFront(task.id, ActivityManager.MOVE_TASK_WITH_HOME);
        }
    }

    /*
    public void openPowerMenu() {
        Log.d(TAG, "Long press power button");
        shiftFloat(FLOAT_VIEW_TYPE.FLOAT_BUTTON);

        //inject();

        //InputManager.getInstance().injectInputEvent(key_event);
        //new Instrumentation().sendKeySync(key_event);
        //window_manager.injectKeyEvent(key_event);


        //Intent intent = new Intent("/");
        //intent.setComponent(new ComponentName("com.android.settings", "com.android.settings.RunningServices"));
        //intent.setAction("android.intent.action.MAIN");
        //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
        //context.startActivity(intent);


    }
    */

    /*private void inject() {
        new Thread() {
            @Override
            public void run() {
                long t = SystemClock.uptimeMillis();
                KeyEvent down_event = new KeyEvent(t, t, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_POWER, 0,
                        0, -1, 0, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, InputDevice.SOURCE_KEYBOARD);


                Class<?> ClassInputManager;
                try {
                    ClassInputManager = Class.forName("android.hardware.input.InputManager");
                    Method[] methods = ClassInputManager.getMethods();
                    Log.d(TAG, "Method All: " + Arrays.toString(methods)); //System.out.println("cchen " + Arrays.toString(methods));
                    Method methodInjectInputEvent = null;
                    Method methodGetInstance = null;
                    for (Method method : methods) {
                        Log.d(TAG, "Method: " + method.getName()); // System.out.println("cchen " + method.getName());
                        if (method.getName().contains("getInstance")) {
                            methodGetInstance = method;
                        }
                        if (method.getName().contains("injectInputEvent")) {
                            methodInjectInputEvent = method;
                        }
                    }
                    Object instance = methodGetInstance.invoke(ClassInputManager, null);
                    boolean bool = InputManager.class.isInstance(instance);
                    Log.d(TAG, "Have instance: " + bool); // System.out.println("cchen  -- " + bool);
                    // methodInjectInputEvent =
                    // InputManager.getMethod("injectInputEvent",
                    // KeyEvent.class, Integer.class);

                    methodInjectInputEvent.invoke(instance, down_event, 0);

                    sleep(2000);

                    KeyEvent up_event = new KeyEvent(t, SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, KeyEvent.KEYCODE_POWER, 0,
                            0, -1, 0, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY, InputDevice.SOURCE_KEYBOARD);

                    methodInjectInputEvent.invoke(instance, up_event, 0);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }*/
}
